[アップデート]AWS ワークロードのネットワークパフォーマンスを監視するCloudWatch Network Monitoring Flow Monitorsが発表されました #AWSreInvent
re:Invent2024に参加している。たかやまです。
CloudWatchで、新たにAWSワークロードのネットワークパフォーマンスを監視できるフローモニターがリリースされました。
Network Flow Monitors とは
概要 :
Network Flow Monitors を使用すると、VPC ネットワーク内の TCP ベースのトラフィックで発生するレイテンシとパケット損失に関するほぼリアルタイムのメトリクスを取得できるようになります。これらのメトリクスを見ることで、ワークロードトラフィックのネットワーク問題の追跡および調査に活用することができます。
また、AWS ワークロードでネットワークの劣化が発生した場合、Network Flow Monitors を使用することで、問題の原因がアプリケーションのワークロードにあるか、基盤となる AWS インフラストラクチャにあるかを判断することも可能になります。
Flow Monitorの監視項目 :
- Agents
- Top contributors
- Local and remote resources
- Workload insights
- Monitors
- Network health indicator (NHI)
- Scope
- Query ID
- Performance metricss
詳細 : Components and features of Network Flow Monitor - Amazon CloudWatch
料金 :
Network Flow Monitorsは利用する監視リソースとCloudWatchメトリクスごとに料金が発生します。
詳細についてはAmazon CloudWatch 料金の「Network Monitoring」 > 「Flow Monitor」を確認してください。
やってみる
Network Flow Monitorsを有効にする
デフォルトでは有効化されていないので「ネットワークモニタリング」 > 「フローモニター」から、サービスロールの追加に問題がなければネットワークフローモニターを有効にする
を選択します。
私の環境ではステータスが「保留中」のまま、5分程度かかりました。
有効化が完了すると、以下のように表示されます。
サンプルアプリケーションをデプロイとエージェントインストール
次に診断対象となるシンプルなマルチAZのEC2のWebサイトをCDKで作成します。
CDKコード
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import * as targets from 'aws-cdk-lib/aws-elasticloadbalancingv2-targets';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
import 'source-map-support/register';
class MultiAzEc2Stack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const vpc = new ec2.Vpc(this, 'MyVPC', {
maxAzs: 2,
subnetConfiguration: [
{
cidrMask: 24,
name: 'Public',
subnetType: ec2.SubnetType.PUBLIC,
}
],
});
const vpcEndpoints = new ec2.InterfaceVpcEndpoint(this, 'SSMEndpoint', {
vpc,
service: ec2.InterfaceVpcEndpointAwsService.SSM,
subnets: { subnetType: ec2.SubnetType.PUBLIC },
privateDnsEnabled: true,
});
new ec2.InterfaceVpcEndpoint(this, 'SSMMessagesEndpoint', {
vpc,
service: ec2.InterfaceVpcEndpointAwsService.SSM_MESSAGES,
subnets: { subnetType: ec2.SubnetType.PUBLIC },
privateDnsEnabled: true,
});
new ec2.InterfaceVpcEndpoint(this, 'EC2MessagesEndpoint', {
vpc,
service: ec2.InterfaceVpcEndpointAwsService.EC2_MESSAGES,
subnets: { subnetType: ec2.SubnetType.PUBLIC },
privateDnsEnabled: true,
});
const ec2SecurityGroup = new ec2.SecurityGroup(this, 'EC2SecurityGroup', {
vpc,
description: 'Security group for EC2 instances',
allowAllOutbound: true,
});
const albSecurityGroup = new ec2.SecurityGroup(this, 'ALBSecurityGroup', {
vpc,
description: 'Security group for ALB',
allowAllOutbound: true,
});
ec2SecurityGroup.addIngressRule(
albSecurityGroup,
ec2.Port.tcp(80),
'Allow HTTP access from ALB'
);
albSecurityGroup.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(80),
'Allow HTTP access from internet'
);
const role = new iam.Role(this, 'EC2Role', {
assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
});
role.addManagedPolicy(
iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore')
);
const alb = new elbv2.ApplicationLoadBalancer(this, 'MyALB', {
vpc,
internetFacing: true,
securityGroup: albSecurityGroup,
});
const targetGroup = new elbv2.ApplicationTargetGroup(this, 'MyTargetGroup', {
vpc,
port: 80,
protocol: elbv2.ApplicationProtocol.HTTP,
targetType: elbv2.TargetType.INSTANCE,
healthCheck: {
path: '/',
healthyHttpCodes: '200',
interval: cdk.Duration.seconds(30),
timeout: cdk.Duration.seconds(5),
},
});
alb.addListener('Listener', {
port: 80,
defaultTargetGroups: [targetGroup],
});
vpc.publicSubnets.forEach((subnet, index) => {
const ec2Instance = new ec2.Instance(this, `EC2Instance-${index + 1}`, {
vpc,
vpcSubnets: {
subnets: [subnet],
},
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.T3,
ec2.InstanceSize.MICRO
),
machineImage: new ec2.AmazonLinuxImage({
generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2023
}),
securityGroup: ec2SecurityGroup,
role: role,
});
ec2Instance.userData.addCommands(
'yum update -y',
'yum install -y httpd',
'systemctl start httpd',
'systemctl enable httpd',
`echo "<h1>Hello from AZ ${subnet.availabilityZone}</h1>" > /var/www/html/index.html`
);
targetGroup.addTarget(new targets.InstanceTarget(ec2Instance));
});
new cdk.CfnOutput(this, 'AlbDnsName', {
value: alb.loadBalancerDnsName,
description: 'The DNS name of the load balancer',
});
}
}
const app = new cdk.App();
new MultiAzEc2Stack(app, 'MultiAzEc2Stack', {
env: {
region: 'ap-northeast-1',
},
});
こちらの手順を参考にコンソールからAWS Network Flow Monitoring Agentのインストールを行います。
Systems Managerの「ディストリビューター」から AmazonCloudWatchNetworkFlowMonitorAgent
ドキュメントを検索します。
今回は「1回限りのインストール」を実施します。
対象のインスタンス2台を指定して実行します。
全体的なステータスが「成功」になればインストール完了です。
今回はAmazon Linux 2023でためしていますが、別のAmazon Linux 2ではインストールが失敗したので現時点ではインストール対象となるOSが制限されている可能性があります。
(ドキュメント上では確認できず)
モニターを作成する
次にNetwork Flow Monitors側でモニターを作成します。
ためしにAvailability Zone内のすべてのネットワークを監視するモニターを作成してみます。
作成できると以下のようなモニターが作成されます。
現在は問題なくアクセスできるのでネットワークヘルスインジケーター
は「正常」になっています。
ここで作成したアプリケーション内で100msの遅延と5%のパケットロスをさせてみます。
# iproute-tcパッケージのインストール
sudo dnf install iproute-tc
# ネットワークインターフェース名の確認
ip addr show
# 実行コマンド
sudo tc qdisc add dev ens5 root netem delay 100ms loss 20%
想定ではネットワークヘルスインジケーターあたりが「異常」になるかと思いますが、そういうわけではないようです...(そもそものトラフィックの概要が表示されなくなった?)
このあたりの動作については今後深堀りしていければと思います。
付録 : できなかったEKSでのNetwork Flow Monitors
モニターを作成する前に、モニタリングするアプリケーションとしてOne Observability Workshopのサンプルアプリケーションをデプロイしたいと思います。
CloudShellで以下のコマンド実行します。
curl -O https://raw.githubusercontent.com/aws-samples/one-observability-demo/main/codepipeline-stack.yaml
aws cloudformation create-stack --stack-name Observability-Workshop \
--template-body file://codepipeline-stack.yaml \
--capabilities CAPABILITY_NAMED_IAM \
--parameters ParameterKey=UserRoleArn,ParameterValue=$(aws iam get-role --role-name $(aws sts get-caller-identity --query Arn --output text | awk -F/ '{print $(NF-1)}') --query Role.Arn --output text)
デプロイが完了するとスタック「Services」の「PetSiteUrl」から以下のようなPet Adoptionのサイトを確認することができます。
全体のアーキテクチャは以下のようになっています。
こちらのEKSクラスターに、エージェントをインストールしていきたいと思います。
引用 : One Observability Workshop
こちらの手順を参考にコンソールからAWS Network Flow Monitoring Agentのインストールを行います。
EKSクラスターの「アドオンをさらに追加」から「AWS Network Flow Monitoring Agent」をインストールします。
アドオン設定では今回は「推奨ロールを作成」を使ってロールを作っていきたいと思います。
「EKS - Pod Identity」に対して CloudWatchNetworkFlowMonitorAgentPublishPolicy
ポリシーをアタッチします。
さきほどの画面で作成したAmazonEKSPodidentityAWSNetworkFlowMonitoringAgentRole
を付与します。
こちらの設定でアドオンを追加します。
追加しましたが、以下のエラーが発生していました...
Amazon EKS Pod Identity agent is not installed in the cluster. To use EKS Pod Identity to grant AWS permissions to pods through Kubernetes service accounts, install the Amazon EKS Pod Identity agent
エラーメッセージに従いAmazon EKS Pod Identity Agent
をインストールします。
そのうえでなお、情報収集はされなかったので、今回はここで断念しました...
(社内でも試したメンバーがいましたが、同様の結果でした)
最後に
CloudWatch Network Flow Monitorsを紹介しました。
検証したうえで、機能として安定していなさそうな部分や正直未知数な部分もあるので、このあたりは今後も検証をつづけていけたらと思います。
この記事が誰かのお役に立てれば幸いです。
以上、たかやま(@nyan_kotaroo)でした。